#include <Windows.h>
#include <detours.h>

#pragma comment(lib, "detours.lib")

struct ExportContext
{
	BOOL    fHasOrdinal1;
	ULONG   nExports;
};

static BOOL CALLBACK ExportCallback(PVOID pContext,
									ULONG nOrdinal,
									PCHAR pszSymbol,
									PVOID pbTarget)
{
	(void)pContext;
	(void)pbTarget;
	(void)pszSymbol;

	ExportContext *pec = (ExportContext *)pContext;

	if (nOrdinal == 1) {
		pec->fHasOrdinal1 = TRUE;
	}
	pec->nExports++;

	return TRUE;
}

int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
	OutputDebugString("Try to Load HookTest with HookDll\n");
	PCHAR pszDllPath = "d:\\Projects\\HookApi\\Debug\\HookDll.dll";
	CHAR szDllPath[1024];
	PCHAR pszFilePart = NULL;

    if (!GetFullPathName(pszDllPath, ARRAYSIZE(szDllPath), szDllPath, &pszFilePart)) {
		OutputDebugString("GetNameFailed!\n");
		return -1;
	}

	HMODULE hDll = LoadLibraryEx(pszDllPath, NULL, DONT_RESOLVE_DLL_REFERENCES);
	if (hDll == NULL) {
		OutputDebugString("Load Dll Failed\n");
		return -1;
	}

	ExportContext ec;
	ec.fHasOrdinal1 = FALSE;
	ec.nExports = 0;
	DetourEnumerateExports(hDll, &ec, ExportCallback);
	FreeLibrary(hDll);

	if (!ec.fHasOrdinal1) 
	{
		OutputDebugString("No ExportTable Found!\n");
		return -1;
	}

	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	CHAR szCommand[2048];
	CHAR szExe[] = "HookTest.exe";
	CHAR szFullExe[1024] = "\0";
	PCHAR pszFileExe = NULL;

	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&pi, sizeof(pi));
	si.cb = sizeof(si);

	szCommand[0] = '\0';

	DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED;

	SetLastError(0);
	SearchPath(NULL, szExe, ".exe", ARRAYSIZE(szFullExe), szFullExe, &pszFileExe);

	if (!DetourCreateProcessWithDll(szFullExe[0] ? szFullExe : NULL, szCommand,
		NULL, NULL, TRUE, dwFlags, NULL, NULL,
		&si, &pi, szDllPath, NULL))
	{
		OutputDebugString("CreateProcessFailed!\n");
		return -1;
	}

	ResumeThread(pi.hThread);

	WaitForSingleObject(pi.hProcess, INFINITE);

	DWORD dwResult = 0;
	if (GetExitCodeProcess(pi.hProcess, &dwResult))
	{
		OutputDebugString("ExitProcess()\n");
	}

	return 0;
}
